-- fulladd_sat.vhd
-- 100910 Mathias Lundell
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;

ENTITY fulladd_sat IS
    GENERIC ( WIDTH : NATURAL := 4 );
    PORT ( a        : IN  STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           b        : IN  STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           cin      : IN  STD_LOGIC;
           saturate : IN  STD_LOGIC;
           
           s        : OUT STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           overflow : OUT STD_LOGIC );   
END ENTITY fulladd_sat;

ARCHITECTURE fulladd_sat_arch OF fulladd_sat IS
    -- Adder of 2 bits
    COMPONENT add2b
        PORT ( a    : IN  STD_LOGIC;
               b    : IN  STD_LOGIC;
               cin  : IN  STD_LOGIC;
          
               s    : OUT STD_LOGIC;
               cout : OUT STD_LOGIC );
    END COMPONENT;
    
    -- Internal "buffer" signals
    SIGNAL n_cout : STD_LOGIC_VECTOR( WIDTH   DOWNTO 0 );
    SIGNAL n_s    : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
    SIGNAL ovf    : STD_LOGIC;
    
    -- Constant zeroes and ones
    CONSTANT c_zeroes : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 ) := (OTHERS => '0');
    CONSTANT c_ones   : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 ) := (OTHERS => '1');
BEGIN
    -- Generate the full adder
    n_cout(0) <= cin;
    FA_generate: FOR i IN 0 TO WIDTH-1 GENERATE
        FA_i: add2b PORT MAP ( a(i), b(i), n_cout(i), n_s(i), n_cout(i+1) );
    END GENERATE;
    
    -- Check overflow
    ovf <= n_cout(WIDTH) XOR n_cout(WIDTH-1);
    overflow <= ovf; 
         
    -- Sum saturated when overflow = 1 else n_s
    s <= '0' &   c_ones( WIDTH-2 DOWNTO 0 ) WHEN 
            (saturate = '1' AND ovf = '1' AND a(WIDTH-1) = '0') ELSE
         '1' & c_zeroes( WIDTH-2 DOWNTO 0 ) WHEN 
            (saturate = '1' AND ovf = '1' AND a(WIDTH-1) = '1') ELSE
         n_s;
         
END ARCHITECTURE fulladd_sat_arch;

